package beans.operacional;

import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UICommand;
import javax.faces.model.SelectItem;
import javax.persistence.Query;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import org.ajax4jsf.component.html.HtmlAjaxCommandButton;
import pojo.cadastro.operacional.Estoque;
import pojo.cadastro.financeiro.FormaPagamento;
import pojo.cadastro.operacional.Produto;
import pojo.cadastro.financeiro.TipoLancamento;
import pojo.operacional.Venda;
import pojo.operacional.VendaItem;
import pojo.operacional.VendaLancamento;

public class VendaBean implements Serializable{

    @PersistenceContext
    private EntityManager mgr;
    private String mensagemErros;

    // pojo
    private long id;
    private int qtdParcelas;
    private double valor;
    private String formaPagamentoId;

    // Campos de Pesquisa
    private Date dataCadastroIni;
    private Date dataCadastroFim;
    
    // Campos de pesquisa e sub-cadastro interno do cadastro
    private String produtoId;
    private String produtoDescricao;
    private String produtoTamanho;
    private int produtoQuantidade;
    private double produtoValorUnitario;
    private double produtoValorDesconto;
    private double produtoValorTotal;
    private String marcaId;
    private String marcaDescricao;

    // Campos de Pesquisa sub-cadastro interno
    private String produtoDescricaoPesq;
    
    // listas
    private List<Venda> listaVendas;
    private List<VendaItem> listaVendaItems;
    private List<VendaLancamento> listaVendaLancamentos;
    private List<Produto> listaProdutos;

    private double totalItems;
    
    // botoes de comandos
    private UICommand btnImprimir;
    private UICommand btnExcluir;
    private HtmlAjaxCommandButton btnSelecionarProduto;
    private HtmlAjaxCommandButton btnExcluirItem;

    public VendaBean() {
    }

    public String pesquisar() {
        carregar();
        return "pesquisa";
    }

    public String retornar() {
        return "pesquisa";
    }

    public String carregar() {

        listaVendas = Collections.EMPTY_LIST;
        String sql = "SELECT v FROM Venda v WHERE v.cancelado = 0 ";
        if (this.dataCadastroIni != null)
            sql += "AND v.dataCadastro >= :dataCadastroIni ";
        if (this.dataCadastroFim != null)
            sql += "AND v.dataCadastro >= :dataCadastroFim ";

        sql += "ORDER BY v.dataCadastro";

        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Query q1 = mgr.createQuery(sql);

        if (this.dataCadastroIni != null)
            q1.setParameter("dataCadastroIni", dataCadastroIni);
        if (this.dataCadastroFim != null)
            q1.setParameter("dataCadastroFim", dataCadastroFim);

        listaVendas = q1.getResultList();
        mgr.close();

        return null;
    }

    public boolean validarFormulario() {

        mensagemErros = "";
        boolean erro = false;
        double totalLancamentos = 0;

        for (int i = 0; i < listaVendaLancamentos.size(); i++) {
            totalLancamentos += listaVendaLancamentos.get(i).getValor();
        }

        mensagemErros = "<FONT COLOR=RED><UL>\n";

        if (listaVendaItems.isEmpty()) {
            mensagemErros = mensagemErros + "<LI>Informar itens.</LI>\n";
            erro = true;
        }
        if (listaVendaLancamentos.isEmpty()) {
            mensagemErros = mensagemErros + "<LI>Informar pelo menos uma parcela.</LI>\n";
            erro = true;
        }
        for (int i = 0; i < listaVendaLancamentos.size(); i++) {
            if (listaVendaLancamentos.get(i).getFormaPagamento().getId() == 0 && !erro) {
                mensagemErros = mensagemErros + "<LI>Todas as Formas de Pagamento devem ser preenchidas.</LI>\n";
                erro = true;
            }
        }
        if (valor != totalLancamentos) {
            mensagemErros = mensagemErros + "<LI>O valor dos lançamentos devem ser igual ao valor dos itens.</LI>\n";
            erro = true;
        }
        mensagemErros = mensagemErros + "</UL></FONT>\n";

        return erro;

    }

    public String salvar() {

        if (validarFormulario()) {
            return null;
        }
        
        Venda v = new Venda();

        if (id != 0) {
            v.setId(id);
        }

        v.setQtdParcelas(qtdParcelas);
        v.setDataCadastro(new Date(System.currentTimeMillis()));
        v.setValor(valor);
        v.setVendaItems(listaVendaItems);
        v.setVendaLancamentos(listaVendaLancamentos);
        TipoLancamento tl = new TipoLancamento();
        tl.setId(1);
        v.setTipoLancamento(tl);

        for (int i = 0;i<listaVendaItems.size();i++) {
            listaVendaItems.get(i).setVenda(v);
        }

        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();

        FormaPagamento fp;
        for (int i = 0;i<listaVendaLancamentos.size();i++) {
            listaVendaLancamentos.get(i).setVenda(v);

            fp = mgr.find(FormaPagamento.class, listaVendaLancamentos.get(i).getFormaPagamento().getId());
            listaVendaLancamentos.get(i).setFormaPagamento(fp);

            if (listaVendaLancamentos.get(i).getFormaPagamento().isBaixaAutomatica()) {
                listaVendaLancamentos.get(i).setDataPagamento(new Date(System.currentTimeMillis()));
            }

        }

        mgr.getTransaction().begin();
        try {
            for (int i = 0;i<listaVendaItems.size();i++) {
                Estoque e = mgr.find(Estoque.class, listaVendaItems.get(i).getProduto().getEstoque().getId());
                e.setQuantidade(e.getQuantidade()-listaVendaItems.get(i).getQuantidade());
                mgr.merge(e);
                listaVendaItems.get(i).setVenda(v);
            }

            if (v.getId() == 0) {
                mgr.persist(v);
            } else {
                mgr.merge(v);
            }
            mgr.getTransaction().commit();
        } catch (Exception e) {
            mensagemErros = "<FONT COLOR=RED><UL>\n";
            mensagemErros = mensagemErros + "<LI>Erro inesperado ao efetuar a Venda! Contate o administrador do sistema.</LI>\n";
            mensagemErros = mensagemErros + "</UL></FONT>\n";
            Logger.getAnonymousLogger().log(Level.SEVERE,"Falha ao cadastrar Venda",e);
            if (mgr.getTransaction().isActive()) {
                mgr.getTransaction().rollback();
            }
            return null;
        } finally {
            mgr.close();
        }

        listaVendas = Collections.EMPTY_LIST;

        return "pesquisa";
    }

    public String incluir() {
        id = 0;
        qtdParcelas = 1;
        listaProdutos = new ArrayList<Produto>();
        listaVendaItems = new ArrayList<VendaItem>();
        listaVendaLancamentos = new ArrayList<VendaLancamento>();
        formaPagamentoId = "";
        valor = 0;
        mensagemErros = "";
        totalItems = 0;

        limpaFormItem();

        return "cadastro";
    }

    public String cancelar() {
        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Venda v = mgr.find(Venda.class, Long.parseLong(btnExcluir.getValue().toString()));
        v.setCancelado(true);
        listaVendaItems = v.getVendaItems();
        mgr.getTransaction().begin();
        try {
            for (int i = 0;i<listaVendaItems.size();i++) {
                Estoque e = mgr.find(Estoque.class, listaVendaItems.get(i).getProduto().getEstoque().getId());
                e.setQuantidade(e.getQuantidade()+listaVendaItems.get(i).getQuantidade());
                mgr.merge(e);
                listaVendaItems.get(i).setVenda(v);
            }
            mgr.merge(v);
            mgr.getTransaction().commit();
        } catch (Exception e) {
            mensagemErros = "<FONT COLOR=RED><UL>\n";
            mensagemErros = mensagemErros + "<LI>Erro inesperado ao efetuar cancelamento da Venda! Contate o administrador do sistema.</LI>\n";
            mensagemErros = mensagemErros + "</UL></FONT>\n";
            Logger.getAnonymousLogger().log(Level.SEVERE,"Falha ao cancelar Venda",e);
            if (mgr.getTransaction().isActive()) {
                mgr.getTransaction().rollback();
            }
            return null;
        } finally {
            mgr.close();
        }
        carregar();

        return null;
    }

    public String imprimir() {
        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Venda v = mgr.find(Venda.class, Long.parseLong(btnImprimir.getValue().toString()));

        id = v.getId();
        listaVendaItems = v.getVendaItems();
        listaVendaLancamentos = v.getVendaLancamentos();
        Collections.sort(listaVendaLancamentos, new Comparator() {
            public int compare(Object o1, Object o2) {
                VendaLancamento vl1 = (VendaLancamento) o1;
                VendaLancamento vl2 = (VendaLancamento) o2;
                return vl1.getDataVencimento().getTime() > vl2.getDataVencimento().getTime() ? +1 : (vl1.getDataVencimento().getTime() < vl2.getDataVencimento().getTime() ? -1 : 0);
            }
        });

        return "imprimir";
    }

    // Pesquisa de Produto
    public String buscarProduto() {
        if (produtoId.equals(""))
            return null;
        
        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Produto p = mgr.find(Produto.class, Long.parseLong(produtoId));

        if (p == null) {
           produtoId = "";
           return null;
        }
        if (p.getEstoque().getQuantidade() <= 0){
            produtoId = "";
            produtoDescricao = p.getDescricao() + " (Indisponível)";
            produtoQuantidade = 0;
        } else {
            produtoId = String.valueOf(p.getId());
            produtoDescricao = p.getDescricao();
            produtoQuantidade = 1;
        }
        produtoValorUnitario = p.getValorVenda();
        produtoTamanho = p.getTamanho();
        produtoValorDesconto = 0;
        produtoValorTotal = p.getValorVenda();
        marcaId = String.valueOf(p.getMarca().getId());
        marcaDescricao = p.getMarca().getDescricao();

        calculaValor();
        
        return null;
    }

    public String calculaTotal() {
        produtoValorTotal = (produtoValorUnitario * produtoQuantidade) - produtoValorDesconto;
        return null;
    }

    public String pesquisarProduto() {
        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Query q1 = mgr.createNamedQuery("Produto.queryByDescricao");
        q1.setParameter("descricaoPesq", "%" + produtoDescricaoPesq + "%");
        this.listaProdutos = q1.getResultList();
        return null;
    }

    public String selecionarProduto() {
        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Produto p = mgr.find(Produto.class, Long.parseLong(btnSelecionarProduto.getValue().toString()));

        if (p == null) {
           produtoId = "";
           return null;
        }

        if (p.getEstoque().getQuantidade() <= 0){
            produtoId = "";
            produtoDescricao = p.getDescricao() + " (Indisponível)";
            produtoQuantidade = 0;
        } else {
            produtoId = String.valueOf(p.getId());
            produtoDescricao = p.getDescricao();
            produtoQuantidade = 1;
        }
        produtoValorUnitario = p.getValorVenda();
        produtoTamanho = p.getTamanho();
        produtoValorDesconto = 0;
        produtoValorTotal = p.getValorVenda();
        marcaId = String.valueOf(p.getMarca().getId());
        marcaDescricao = p.getMarca().getDescricao();

        calculaValor();

        return null;
    }

    // Formulário de incluão e tabela de itens.
    public void limpaFormItem() {
        produtoId = "";
        produtoDescricao = "";
        produtoTamanho = "";
        produtoQuantidade = 0;
        produtoValorUnitario = 0;
        produtoValorDesconto = 0;
        produtoValorTotal = 0;
        marcaId = "";
        marcaDescricao = "";
    }

    public String incluirItem() {
        if (produtoId.equals("")) {
            return null;
        }

        VendaItem vit = new VendaItem();
        Produto p = mgr.find(Produto.class, Long.parseLong(produtoId));
        vit.setProduto(p);
        vit.setQuantidade(produtoQuantidade);
        vit.setValorUnitario(produtoValorUnitario);
        vit.setValorDesconto(produtoValorDesconto);
        vit.setValorTotal(produtoValorTotal);
        listaVendaItems.add(vit);

        limpaFormItem();
        calculaValor();

        return null;
    }

    public String excluirItem() {
        listaVendaItems.remove(Integer.parseInt(btnExcluirItem.getValue().toString()));
        calculaValor();
        return null;
    }

    // Para controle de lancamentos
    public void calculaValor() {
        valor = 0;
        for (VendaItem vi : listaVendaItems) {
            valor += vi.getValorTotal();
        }
        totalItems = valor;
        actionCarregaLancamentos();
    }

    public String actionCarregaLancamentos() {
        DecimalFormat df = new DecimalFormat();
        df.setMaximumFractionDigits(2);

        Calendar cal = Calendar.getInstance();
        FormaPagamento fp;
        VendaLancamento vl;
        double valorLancamento = 0;
        double somaLancamentos = 0;

        listaVendaLancamentos.clear();

        for (int i = 1; i <= qtdParcelas; i++) {
            vl = new VendaLancamento();
            vl.setNumParcela(i);
            vl.setDataVencimento(cal.getTime());
            fp = new FormaPagamento();
            if (!formaPagamentoId.equals("")) {
                fp.setId(Long.parseLong(formaPagamentoId));
            }
            vl.setFormaPagamento(fp);
            valorLancamento = valor / qtdParcelas;

            somaLancamentos += (Double.parseDouble(df.format(valorLancamento).toString().replace(".", "").replace(",", ".")));
            if (i == qtdParcelas) {
                if (somaLancamentos < valor) {
                    valorLancamento += (valor - somaLancamentos);
                }
            }
            vl.setValor(valorLancamento);

            listaVendaLancamentos.add(vl);

            cal.add(Calendar.MONTH, 1);
        }
        return null;
    }

    public String actionReplicaFormaPagamento() {
        if (formaPagamentoId.equals("")) {
            return null;
        }

        FormaPagamento fp;
        for (int i = 0; i < listaVendaLancamentos.size(); i++) {
            fp = new FormaPagamento();
            fp.setId(Long.parseLong(formaPagamentoId));
            listaVendaLancamentos.get(i).setFormaPagamento(fp);
        }
        return null;
    }

    // Getters and Setters
    public List<SelectItem> getListaFormaPagamentos() {
        mgr = Persistence.createEntityManagerFactory("lojaPU").createEntityManager();
        Query q1 = mgr.createNamedQuery("FormaPagamento.listAll");
        List<SelectItem> items = new ArrayList<SelectItem>();

        for (FormaPagamento fp : (List<FormaPagamento>) q1.getResultList()) {
            items.add(new SelectItem(fp.getId(), fp.getDescricao()));
        }

        mgr.close();
        return items;
    }

    public UICommand getBtnImprimir() {
        return btnImprimir;
    }

    public void setBtnImprimir(UICommand btnImprimir) {
        this.btnImprimir = btnImprimir;
    }

    public UICommand getBtnExcluir() {
        return btnExcluir;
    }

    public void setBtnExcluir(UICommand btnExcluir) {
        this.btnExcluir = btnExcluir;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public List<Produto> getListaProdutos() {
        return listaProdutos;
    }

    public void setListaProdutos(List<Produto> listaProdutos) {
        this.listaProdutos = listaProdutos;
    }

    public List<VendaItem> getListaVendaItems() {
        return listaVendaItems;
    }

    public void setListaVendaItems(List<VendaItem> listaVendaItems) {
        this.listaVendaItems = listaVendaItems;
    }

    public List<VendaLancamento> getListaVendaLancamentos() {
        return listaVendaLancamentos;
    }

    public void setListaVendaLancamentos(List<VendaLancamento> listaVendaLancamentos) {
        this.listaVendaLancamentos = listaVendaLancamentos;
    }

    public List<Venda> getListaVendas() {
        return listaVendas;
    }

    public void setListaVendas(List<Venda> listaVendas) {
        this.listaVendas = listaVendas;
    }

    public String getProdutoDescricao() {
        return produtoDescricao;
    }

    public void setProdutoDescricao(String produtoDescricao) {
        this.produtoDescricao = produtoDescricao;
    }

    public String getProdutoId() {
        return produtoId;
    }

    public void setProdutoId(String produtoId) {
        this.produtoId = produtoId;
    }

    public int getProdutoQuantidade() {
        return produtoQuantidade;
    }

    public void setProdutoQuantidade(int produtoQuantidade) {
        this.produtoQuantidade = produtoQuantidade;
    }

    public double getProdutoValorTotal() {
        return produtoValorTotal;
    }

    public void setProdutoValorTotal(double produtoValorTotal) {
        this.produtoValorTotal = produtoValorTotal;
    }

    public double getProdutoValorDesconto() {
        return produtoValorDesconto;
    }

    public void setProdutoValorDesconto(double produtoValorDesconto) {
        this.produtoValorDesconto = produtoValorDesconto;
    }

    public double getProdutoValorUnitario() {
        return produtoValorUnitario;
    }

    public void setProdutoValorUnitario(double produtoValorUnitario) {
        this.produtoValorUnitario = produtoValorUnitario;
    }

    public String getProdutoTamanho() {
        return produtoTamanho;
    }

    public void setProdutoTamanho(String produtoTamanho) {
        this.produtoTamanho = produtoTamanho;
    }

    public int getQtdParcelas() {
        return qtdParcelas;
    }

    public void setQtdParcelas(int qtdParcelas) {
        this.qtdParcelas = qtdParcelas;
    }

    public String getProdutoDescricaoPesq() {
        return produtoDescricaoPesq;
    }

    public void setProdutoDescricaoPesq(String produtoDescricaoPesq) {
        this.produtoDescricaoPesq = produtoDescricaoPesq;
    }

    public HtmlAjaxCommandButton getBtnSelecionarProduto() {
        return btnSelecionarProduto;
    }

    public void setBtnSelecionarProduto(HtmlAjaxCommandButton btnSelecionarProduto) {
        this.btnSelecionarProduto = btnSelecionarProduto;
    }

    public HtmlAjaxCommandButton getBtnExcluirItem() {
        return btnExcluirItem;
    }

    public void setBtnExcluirItem(HtmlAjaxCommandButton btnExcluirItem) {
        this.btnExcluirItem = btnExcluirItem;
    }

    public String getMarcaDescricao() {
        return marcaDescricao;
    }

    public void setMarcaDescricao(String marcaDescricao) {
        this.marcaDescricao = marcaDescricao;
    }

    public String getMarcaId() {
        return marcaId;
    }

    public void setMarcaId(String marcaId) {
        this.marcaId = marcaId;
    }

    public String getFormaPagamentoId() {
        return formaPagamentoId;
    }

    public void setFormaPagamentoId(String formaPagamentoId) {
        this.formaPagamentoId = formaPagamentoId;
    }

    public double getValor() {
        return valor;
    }

    public void setValor(double valor) {
        this.valor = valor;
    }

    public String getMensagemErros() {
        return mensagemErros;
    }

    public void setMensagemErros(String mensagemErros) {
        this.mensagemErros = mensagemErros;
    }

    public double getTotalItems() {
        return totalItems;
    }

    public void setTotalItems(double totalItems) {
        this.totalItems = totalItems;
    }

    public Date getDataCadastroFim() {
        return dataCadastroFim;
    }

    public void setDataCadastroFim(Date dataCadastroFim) {
        this.dataCadastroFim = dataCadastroFim;
    }

    public Date getDataCadastroIni() {
        return dataCadastroIni;
    }

    public void setDataCadastroIni(Date dataCadastroIni) {
        this.dataCadastroIni = dataCadastroIni;
    }
    
}